package com.joysuch.wwyt.bp.service.impl;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.joysuch.wwyt.bp.bean.risk.*;
import com.joysuch.wwyt.bp.entity.BpDepart;
import com.joysuch.wwyt.bp.entity.risk.BpJudgeDepart;
import com.joysuch.wwyt.bp.entity.risk.BpTeam;
import com.joysuch.wwyt.bp.enums.RiskJudgeStates;
import com.joysuch.wwyt.bp.repository.BpDepartDao;
import com.joysuch.wwyt.bp.repository.BpDepartRepository;
import com.joysuch.wwyt.bp.repository.BpTeamRepository;
import com.joysuch.wwyt.bp.service.BpRiskDepartService;
import com.joysuch.wwyt.bp.service.BpTeamService;
import com.joysuch.wwyt.core.common.ajax.ResultBean;
import com.joysuch.wwyt.core.common.util.PageDataUtils;
import com.joysuch.wwyt.core.entity.BaseUser;
import com.joysuch.wwyt.core.repository.BaseUserDao;
import com.joysuch.wwyt.core.support.Context;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @Author ZhangDong
 * @Date 2020/3/5 17:19
 */
@Service
@Slf4j
@Transactional
public class BpRiskDepartServiceImpl implements BpRiskDepartService {

    @Autowired
    private BpDepartDao bpDepartDao;
    @Autowired
    private BaseUserDao baseUserDao;
    @Autowired
    private BpTeamService bpTeamService;
    @Autowired
    private BpTeamRepository bpTeamRepository;
    @Autowired
    private BpDepartRepository bpDepartRepository;

    @Override
    public ResultBean save(BpDepartBean bpDepartBean) {
        Long currentDepartId = getCurrentDepartId();
        Long id = bpDepartBean.getId();
        /*LocalDate reportDate = bpDepartBean.getReportDate();
        Long higherDepartId = bpDepartBean.getHigherDepartId();*/

        BpJudgeDepart bpJudgeDepart;
        if (id == null) {
            //放开，可以多次
            /*//新增：同一部门，同一天只能上报一次
            List<BpJudgeDepart> tempList = bpDepartRepository.findByReportDateAndHigherDepartId(reportDate, higherDepartId);
            if (!CollectionUtils.isEmpty(tempList)) {
                return ResultBean.fail(101, "同一部门同一天只能上报一次");
            }*/
            bpJudgeDepart = new BpJudgeDepart();
            bpJudgeDepart.setReleaseStatus(RiskJudgeStates.WAIT_COMMIT.getState());
        } else {
            bpJudgeDepart = bpDepartRepository.findById(id).orElse(null);
            //修改只有当前部门
            if (currentDepartId != null && !currentDepartId.equals(bpJudgeDepart.getHigherDepartId())) {
                return ResultBean.fail(101, "没有权限");
            }
            /*if (!reportDate.isEqual(bpJudgeDepart.getReportDate())) {
                List<BpJudgeDepart> tempList = bpDepartRepository.findByReportDateAndHigherDepartId(reportDate, higherDepartId);
                if (!CollectionUtils.isEmpty(tempList)) {
                    return ResultBean.fail(101, "同一部门同一天只能上报一次");
                }
            }*/
        }
        BeanUtils.copyProperties(bpDepartBean, bpJudgeDepart);
        //特种作业
        bpJudgeDepart.setSpecialWork(JSON.toJSONString(bpDepartBean.getSpecialBeanList()));
        //班组上报材料
        bpJudgeDepart.setTeamIds(JSON.toJSONString(bpDepartBean.getTeamIdList()));
        bpDepartRepository.save(bpJudgeDepart);
        return ResultBean.defaultSuccessResult();
    }

    @Override
    public ResultBean getById(Long id) {
        BpJudgeDepart bpJudgeDepart = bpDepartRepository.findById(id).orElse(null);
        if (bpJudgeDepart == null) {
            return ResultBean.wrapErrorResultDefault("系统繁忙");
        }
        BpDepartDto dto = new BpDepartDto();
        BeanUtils.copyProperties(bpJudgeDepart, dto);
        //特种作业
        dto.setSpecialBeanList(JSON.parseArray(bpJudgeDepart.getSpecialWork(), BpTeamSpecialBean.class));
        dto.setJudgeUserName(baseUserDao.getBaseUserNameById(bpJudgeDepart.getJudgeUserId()));
        dto.setPromiseUserName(baseUserDao.getBaseUserNameById(bpJudgeDepart.getPromiseUserId()));
        dto.setHigherDepartName(bpDepartDao.findDepartNameById(bpJudgeDepart.getHigherDepartId()));
        dto.setReportUserName(baseUserDao.getBaseUserNameById(bpJudgeDepart.getReportUserId()));
        //班组上报材料
        List<Long> teamIds = JSON.parseArray(bpJudgeDepart.getTeamIds(), Long.class);
        List<BpTeam> bpTeamList = teamIds.stream().map(r -> bpTeamRepository.findById(r).orElse(null)).collect(Collectors.toList());
        List<BpTeamDetailDto> detailDtoList = bpTeamList.stream().map(r -> {
            String reportUserName = baseUserDao.getBaseUserNameById(r.getReportUserId());
            String departName = bpDepartDao.findDepartNameById(r.getTeamDepartId());
            return new BpTeamDetailDto(r.getId(), departName, r.getReportDate(), reportUserName);
        }).collect(Collectors.toList());
        dto.setDetailDtoList(detailDtoList);
        return ResultBean.success(dto);
    }

    /**
     * @param flag 0 部门级; 1 部门级审核
     */
    @Override
    public ResultBean page(Pageable pageable, LocalDate reportDate, Integer flag) {
        if (flag != 0 && flag != 1) {
            return ResultBean.fail(101, "flag传值错误");
        }
        Long currentDepartId = getCurrentDepartId();
        pageable = PageDataUtils.addOrderByDesc(pageable, "id");
        Specification<BpJudgeDepart> querySpecifi = new Specification<BpJudgeDepart>() {
            @Override
            public Predicate toPredicate(Root<BpJudgeDepart> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb) {
                List<Predicate> predicates = new ArrayList<>();
                if (reportDate != null) {
                    predicates.add(cb.equal(root.get("reportDate"), reportDate));
                }
                //部门级--只限当前部门； 部门级审核--查询所有等待审批
                if (flag == 0 && !Context.getCurrentUser().username.equals("admin")) {
                    predicates.add(cb.equal(root.get("higherDepartId"), currentDepartId));
                } else if (flag == 1){
                    CriteriaBuilder.In<Object> in = cb.in(root.get("releaseStatus"));
                    in.value(RiskJudgeStates.WAIT_APPROVE.getState());
                    in.value(RiskJudgeStates.REPORTED.getState());
                    in.value(RiskJudgeStates.NOT_APPROVE.getState());
                    predicates.add(in);
                }
                return cb.and(predicates.toArray(new Predicate[predicates.size()]));
            }
        };
        Page<BpJudgeDepart> all = bpDepartRepository.findAll(querySpecifi, pageable);
        List<Long> departIdList = all.getContent().stream().map(r -> r.getHigherDepartId()).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        Map<Long, String> departMap = bpDepartDao.findAllById(departIdList).stream().collect(Collectors.toMap(r -> r.getId(), r -> r.getName()));
        for (BpJudgeDepart bpJudgeDepart : all) {
            bpJudgeDepart.setHigherDepartName(departMap.getOrDefault(bpJudgeDepart.getHigherDepartId(), ""));
        }
        return ResultBean.pageData(all.getContent(), all.getTotalElements());
    }

    @Override
    public ResultBean submit(Long id) {
        BpJudgeDepart bpJudgeDepart = bpDepartRepository.findById(id).orElse(null);
        if (bpJudgeDepart == null) {
            return ResultBean.fail(101, "系统正忙");
        }
        Long currentDepartId = getCurrentDepartId();
        if (currentDepartId != null && !currentDepartId.equals(bpJudgeDepart.getHigherDepartId())) {
            return ResultBean.fail(101, "没有权限");
        }
        //新增 审批不通过也可以提交
        String releaseStatus = bpJudgeDepart.getReleaseStatus();
        if (!RiskJudgeStates.WAIT_COMMIT.getState().equals(releaseStatus)
                && !RiskJudgeStates.NOT_APPROVE.getState().equals(releaseStatus)) {
            return ResultBean.fail(101, "不可重复提交");
        }
        bpJudgeDepart.setReleaseStatus(RiskJudgeStates.WAIT_APPROVE.getState());
        bpDepartRepository.save(bpJudgeDepart);
        return ResultBean.defaultSuccessResult();
    }

    @Override
    public ResultBean delete(Long id) {
        //删除权限：本部门
        BpJudgeDepart bpJudgeDepart = bpDepartRepository.findById(id).orElse(null);
        if (bpJudgeDepart == null) {
            return ResultBean.fail(101, "数据不可重复删除");
        }
        Long currentDepartId = getCurrentDepartId();
        Long higherDepartId = bpJudgeDepart.getHigherDepartId();
        if (currentDepartId != null && !currentDepartId.equals(higherDepartId)) {
            return ResultBean.fail(101, "没有权限");
        }
        bpDepartRepository.deleteById(id);
        return ResultBean.defaultSuccessResult();
    }

    /**
     * @param flag 0 不通过; 1 通过
     */
    @Override
    public ResultBean verify(Long id, int flag) {
        if (flag != 0 && flag != 1) {
            return ResultBean.fail(101, "flag传值错误");
        }
        BpJudgeDepart bpJudgeDepart = bpDepartRepository.findById(id).orElse(null);
        if (bpJudgeDepart == null) {
            return ResultBean.fail(101, "系统正忙");
        }
        if (!RiskJudgeStates.WAIT_APPROVE.getState().equals(bpJudgeDepart.getReleaseStatus())) {
            return ResultBean.fail(101, "当前状态不可审批");
        }
        if (flag == 0) {
            bpJudgeDepart.setReleaseStatus(RiskJudgeStates.NOT_APPROVE.getState());
        } else {
            bpJudgeDepart.setReleaseStatus(RiskJudgeStates.REPORTED.getState());
        }
        bpDepartRepository.save(bpJudgeDepart);
        return ResultBean.defaultSuccessResult();
    }

    @Override
    public ResultBean getDepart() {
        Long currentUserId = Context.getCurrentUserId();
        BaseUser baseUser = baseUserDao.findById(currentUserId).orElse(new BaseUser());
        Long departId = baseUser.getDepartId();
        return ResultBean.success(bpDepartDao.findById(departId).orElse(new BpDepart()));
    }

    @Override
    public ResultBean getUser() {
        Long currentUserId = Context.getCurrentUserId();
        BaseUser baseUser = baseUserDao.findById(currentUserId).orElse(new BaseUser());
        baseUser.setBaseLoginAccount(null);
        return ResultBean.success(baseUser);
    }

    @Override
    public ResultBean reportPage(Pageable pageable) {
        ResultBean page = bpTeamService.page(pageable, null, 1);
        BpRiskDepartReportDto dto = new BpRiskDepartReportDto();
        if (page.getCode() == 0) {
            List<BpTeam> bpTeamList = (List<BpTeam>) page.getData();
            if (!CollectionUtils.isEmpty(bpTeamList)) {
                List<BpTeamSpecialBean> specialBeanList = Lists.newArrayList();
                bpTeamList.parallelStream().forEach(r -> {
                    List<BpTeamSpecialBean> beans = JSON.parseArray(r.getSpecialWork(), BpTeamSpecialBean.class);
                    for (BpTeamSpecialBean bean : beans) {
                        specialBeanList.add(bean);
                    }
                });
                List<BpTeamSpecialBean> resultList = Lists.newArrayList();
                Map<String, Integer> map = specialBeanList.stream().collect(Collectors.groupingBy(BpTeamSpecialBean::getSpecialWorkName, Collectors.summingInt(BpTeamSpecialBean::getSum)));
                for (String s : map.keySet()) {
                    Integer sum = map.get(s);
                    resultList.add(new BpTeamSpecialBean(s, sum));
                }
                dto.setBpTeamList(bpTeamList);
                dto.setSpecailBeanList(resultList);
            }
        }
        return ResultBean.success(dto);
    }

    private Long getCurrentDepartId() {
        Long currentUserId = Context.getCurrentUserId();
        BaseUser baseUser = baseUserDao.findById(currentUserId).orElse(new BaseUser());
        return baseUser.getDepartId();
    }
}
